//
// Created by zhengjuping on 24-9-9.
//

#include <utility>
#include <esp_log.h>
#include <esp_gatts_api.h>
#include <cstring>

#include "include/GattCharacteristic.h"

#define TAG "GattCharacteristic"

#define GATTS_DEMO_CHAR_VAL_LEN_MAX 500

#define CHAR_DECLARATION_SIZE       (sizeof(uint8_t))

static const uint8_t default_char_value[4]                 = {0x11, 0x22, 0x33, 0x44};
GattCharacteristic::GattCharacteristic(BleUuid const &uuid,
                                       const uint8_t *defaultValue,
                                       uint32_t defaultValueSize,
                                       ResponseMethod rspMethod,
                                       Properties properties,
                                       Permissions permission ):
                                       _uuid(uuid),
                                       _gattsIf(-1),
                                       _connId(-1),
                                       _handle(0),
                                       _rspMethod(ESP_GATT_AUTO_RSP),
                                       _properties(ESP_GATT_CHAR_PROP_BIT_READ),
                                       _permission(ESP_GATT_PERM_READ),
                                       _defaultValueSize(defaultValueSize),
                                       _max_length( 500 ){

    switch (rspMethod) {
        case ResponseMethod::AUTO_RSP:
            _rspMethod = ESP_GATT_AUTO_RSP;
            break;

        case ResponseMethod::RSP_BY_APP:
            _rspMethod = ESP_GATT_RSP_BY_APP;
            break;

        default:
            break;
    }

    switch (properties) {
        case GattCharacteristic::Properties::Read:{
            _properties = ESP_GATT_CHAR_PROP_BIT_READ;
            break;
        }

        case GattCharacteristic::Properties::Write:{
            _properties = ESP_GATT_CHAR_PROP_BIT_WRITE;
            break;
        }

        case GattCharacteristic::Properties::Notify:{
            _properties = ESP_GATT_CHAR_PROP_BIT_NOTIFY;
            break;
        }

        case GattCharacteristic::Properties::Read_Write_Notify:{
            _properties = ESP_GATT_CHAR_PROP_BIT_READ | ESP_GATT_CHAR_PROP_BIT_WRITE | ESP_GATT_CHAR_PROP_BIT_NOTIFY;
            break;
        }

        default:
            break;
    }

    switch (permission) {
        case Permissions::Read:
            _permission = ESP_GATT_PERM_READ;
            break;

        case Permissions::Write:
            _permission = ESP_GATT_PERM_WRITE;
            break;

        case Permissions::Read_Write:
            _permission = ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE;
            break;

        default:
            break;
    }


    _attr_db.attr_control.auto_rsp = _rspMethod;
    switch (_uuid.getWidth()) {
        case BleUuid::Width::UUID_16:{
            _uuid16 = _uuid.getUuid16();
            _attr_db.att_desc.uuid_p = (uint8_t *)&_uuid16;
            _attr_db.att_desc.uuid_length = 2;
            break;
        }
        case BleUuid::Width::UUID_32:
            _uuid32 = _uuid.getUuid32();
            _attr_db.att_desc.uuid_p = (uint8_t *)&_uuid32;
            _attr_db.att_desc.uuid_length = 4;
            break;
        default:
            abort();
    }
    _attr_db.att_desc.perm = _permission;
    _attr_db.att_desc.max_length = _max_length;
    _attr_db.att_desc.length = _defaultValueSize;
    _defaultValue = (uint8_t *) malloc(_defaultValueSize);
    memcpy(_defaultValue, defaultValue, _defaultValueSize);
    _attr_db.att_desc.value = _defaultValue;
}

const esp_gatts_attr_db_t *GattCharacteristic::getAttrDb() {
    return &_attr_db;
}

void GattCharacteristic::dump(){
    ESP_LOGE(TAG, "autoRsp::%d", _attr_db.attr_control.auto_rsp);
    esp_log_buffer_hex_internal(TAG,_attr_db.att_desc.uuid_p, _attr_db.att_desc.uuid_length, ESP_LOG_WARN);
    ESP_LOGE(TAG, "perm::%d", _attr_db.att_desc.perm);
    ESP_LOGE(TAG, "max_length::%d", _attr_db.att_desc.max_length);
    esp_log_buffer_hex_internal(TAG,_attr_db.att_desc.value, _attr_db.att_desc.length, ESP_LOG_WARN);
}

void GattCharacteristic::setHandle(uint16_t handle) {
    _handle = handle;
}

uint16_t GattCharacteristic::getHandle() const {
    return _handle;
}

void GattCharacteristic::onReadEvent(uint8_t *data, uint16_t &length) {
    ESP_LOGI(TAG, "GattCharacteristic::onReadEvent");
    length = _defaultValueSize;
    memcpy(data, _defaultValue, _defaultValueSize);
}

void GattCharacteristic::onWriteEvent(const uint8_t *data, uint16_t length) {
    ESP_LOGI(TAG, "GattCharacteristic111::onWriteEvent");
    esp_log_buffer_hex_internal(TAG,  data, length, ESP_LOG_WARN);
}

void GattCharacteristic::onNotifyStatusUpdateEvent(bool notifyEnabled) {
    ESP_LOGI(TAG, "GattCharacteristic::onNotifyStatusUpdateEvent:%d", notifyEnabled);
}

void GattCharacteristic::setGattsIf(uint16_t gattsIf) {
    _gattsIf = gattsIf;
}

void GattCharacteristic::setConnId(uint16_t connId) {
    _connId = connId;
}

int32_t GattCharacteristic::sendIndicate(uint8_t *data, uint16_t length) const {
    return esp_ble_gatts_send_indicate(_gattsIf,
                                       _connId,
                                       _handle,
                                       length,
                                       data,
                                       false);
}

uint32_t GattCharacteristic::getProperties() {
    return _properties;
}

void GattCharacteristic::onConnectEvent() {
    ESP_LOGI(TAG, "GattCharacteristic::onConnectEvent");
}

void GattCharacteristic::onDisConnectEvent() {
    ESP_LOGI(TAG, "GattCharacteristic::onDisConnectEvent");
}



